﻿using System;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MugenInjection.Interception.Interface;
using MugenInjection.Interception.Proxy;
using Should;

namespace MugenInjectionTest.Interception
{

    public class ConditionsTest : InterceptionTestBase
    {
        #region Nested types

        #region Nested type: InternalNestedClass

        internal class InternalNestedClass
        {
        }

        #endregion

        #region Nested type: PrivateClass

        private class PrivateClass
        {
        }

        #endregion

        #region Nested type: ProtectedClass

        protected class ProtectedClass
        {
        }

        #endregion

        #region Nested type: PublicNestedClass

        public class PublicNestedClass
        {
        }

        #endregion

        #endregion

        #region Test methods

        [TestMethod]
        public void ClassConditionsTest()
        {
            IProxyFactory proxyFactory = GetProxyFactory();
            Type proxy;
            TestUtils.Catch<ArgumentNullException>(() => proxyFactory.CreateProxy((Type) null, out proxy));
            TestUtils.Catch<ArgumentException>(() => proxyFactory.CreateProxy(typeof (PrivateClass), out proxy));
            TestUtils.Catch<ArgumentException>(() => proxyFactory.CreateProxy(typeof (ProtectedClass), out proxy));

            //Check for interface
            TestUtils.Catch<ArgumentException>(() => proxyFactory.CreateProxy(typeof (IDisposable), out proxy));

            //Check for generic
            TestUtils.Catch<ArgumentException>(() => proxyFactory.CreateProxy(typeof (List<>), out proxy));

            proxyFactory.CreateProxy(typeof (PublicNestedClass), out proxy);
            typeof (PublicNestedClass).IsAssignableFrom(proxy).ShouldBeTrue();
            
            proxyFactory.CreateProxy(typeof (PublicClass), out proxy);
            typeof (PublicClass).IsAssignableFrom(proxy).ShouldBeTrue();
        }

        [TestMethod]
        public void InterfaceConditionsTest()
        {
            IProxyFactory proxyFactory = GetProxyFactory();
            Type proxy;
            TestUtils.Catch<ArgumentNullException>(() => proxyFactory.CreateProxy((Type[]) null, out proxy));
            TestUtils.Catch<ArgumentException>(() => proxyFactory.CreateProxy(new Type[0], out proxy));
            
            //Check for generic
            TestUtils.Catch<ArgumentException>(() => proxyFactory.CreateProxy(new[] {typeof (IList<>)}, out proxy));

            //Check for class
            TestUtils.Catch<ArgumentException>(
                () => proxyFactory.CreateProxy(new[] {typeof (PublicClass), typeof (IDisposable)}, out proxy));

            //Check duplicate
            TestUtils.Catch<ArgumentException>(
                () => proxyFactory.CreateProxy(new[] {typeof (IDisposable), typeof (IDisposable)}, out proxy));

            proxyFactory.CreateProxy(new[] {typeof (IPublicInterface)}, out proxy);
            typeof (IPublicInterface).IsAssignableFrom(proxy).ShouldBeTrue();
        }

        #endregion
    }

    public class PublicClass
    {
    }

    internal class InternalClass
    {
    }

    internal interface IInternalInterface
    {
    }

    public interface IPublicInterface
    {
    }
}